import ReactDOM from "react-dom";
import { useCallback, useEffect, useState, forwardRef, useImperativeHandle, ReactNode } from "react";
import classNames from "classnames";
import styles from "@shared/slide/styles/styles.module.less";

interface Props {
    // 弹层内部要渲染的内容
    children: ReactNode;
    // 弹层滑动方向
    direction: "toTop" | "toLeft" | "toRight";
}

export interface SlideRef {
    // 渲染弹层
    open: () => void;
    // 销毁弹层
    close: () => void;
}

const Slide = forwardRef<SlideRef, Props>(({ children, direction }, ref) => {
    // 用于控制弹层是否渲染和销毁的状态
    const [isRender, setIsRender] = useState(false);
    // 控制是否为弹框元素添加 active 类名(执行动画)
    const [isActive, setIsActive] = useState(false);

    // 检测 isRender 是否为真, 如果是为元素添加 active 类名执行动画
    useEffect(() => {
        // 为元素添加类名执行动画
        if (isRender) setIsActive(true);
    }, [isRender]);

    // 销毁弹层
    const close = useCallback(() => {
        // 删除类名执行动画
        setIsActive(false);
        // 延迟等待动画执行完成
        setTimeout(() => {
            // 销毁弹层
            setIsRender(false);
        }, 300);
    }, [setIsActive, setIsRender]);

    // 渲染弹层
    const open = useCallback(() => {
        setIsRender(true);
    }, [setIsRender]);

    // 在钩子中挂载销毁弹层和渲染弹层的方法供外部使用
    useImperativeHandle(ref, () => ({ open, close }), [open, close]);

    // 根据 isRender 决定是否渲染弹层
    return isRender
        ? ReactDOM.createPortal(
            <div
                onClick={close}
                className={classNames(styles.layer, {
                    [styles.active]: isActive,
                })}
            >
                <div
                    className={classNames(styles.content, {
                        [styles.toTop]: direction === "toTop",
                        [styles.toLeft]: direction === "toLeft",
                        [styles.toRight]: direction === "toRight",
                    })}
                    onClick={(event) => event.stopPropagation()}
                >
                    {children}
                </div>
            </div>,
            document.body
        )
        : null;
});

export default Slide;